/*
 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package javax.sound.midi;

import java.io.InputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;


/**
 * A <code>MidiFileFormat</code> object encapsulates a MIDI file's
 * type, as well as its length and timing information.
 *
 * <p>A <code>MidiFileFormat</code> object can
 * include a set of properties. A property is a pair of key and value:
 * the key is of type <code>String</code>, the associated property
 * value is an arbitrary object.
 * Properties specify additional informational
 * meta data (like a author, or copyright).
 * Properties are optional information, and file reader and file
 * writer implementations are not required to provide or
 * recognize properties.
 *
 * <p>The following table lists some common properties that should
 * be used in implementations:
 *
 * <table border=1>
 * <caption>MIDI File Format Properties</caption>
 * <tr>
 * <th>Property key</th>
 * <th>Value type</th>
 * <th>Description</th>
 * </tr>
 * <tr>
 * <td>&quot;author&quot;</td>
 * <td>{@link java.lang.String String}</td>
 * <td>name of the author of this file</td>
 * </tr>
 * <tr>
 * <td>&quot;title&quot;</td>
 * <td>{@link java.lang.String String}</td>
 * <td>title of this file</td>
 * </tr>
 * <tr>
 * <td>&quot;copyright&quot;</td>
 * <td>{@link java.lang.String String}</td>
 * <td>copyright message</td>
 * </tr>
 * <tr>
 * <td>&quot;date&quot;</td>
 * <td>{@link java.util.Date Date}</td>
 * <td>date of the recording or release</td>
 * </tr>
 * <tr>
 * <td>&quot;comment&quot;</td>
 * <td>{@link java.lang.String String}</td>
 * <td>an arbitrary text</td>
 * </tr>
 * </table>
 *
 * @author Kara Kytle
 * @author Florian Bomers
 * @see MidiSystem#getMidiFileFormat(java.io.File)
 * @see Sequencer#setSequence(java.io.InputStream stream)
 */

public class MidiFileFormat {


  /**
   * Represents unknown length.
   *
   * @see #getByteLength
   * @see #getMicrosecondLength
   */
  public static final int UNKNOWN_LENGTH = -1;


  /**
   * The type of MIDI file.
   */
  protected int type;

  /**
   * The division type of the MIDI file.
   *
   * @see Sequence#PPQ
   * @see Sequence#SMPTE_24
   * @see Sequence#SMPTE_25
   * @see Sequence#SMPTE_30DROP
   * @see Sequence#SMPTE_30
   */
  protected float divisionType;

  /**
   * The timing resolution of the MIDI file.
   */
  protected int resolution;

  /**
   * The length of the MIDI file in bytes.
   */
  protected int byteLength;

  /**
   * The duration of the MIDI file in microseconds.
   */
  protected long microsecondLength;


  /**
   * The set of properties
   */
  private HashMap<String, Object> properties;


  /**
   * Constructs a <code>MidiFileFormat</code>.
   *
   * @param type the MIDI file type (0, 1, or 2)
   * @param divisionType the timing division type (PPQ or one of the SMPTE types)
   * @param resolution the timing resolution
   * @param bytes the length of the MIDI file in bytes, or UNKNOWN_LENGTH if not known
   * @param microseconds the duration of the file in microseconds, or UNKNOWN_LENGTH if not known
   * @see #UNKNOWN_LENGTH
   * @see Sequence#PPQ
   * @see Sequence#SMPTE_24
   * @see Sequence#SMPTE_25
   * @see Sequence#SMPTE_30DROP
   * @see Sequence#SMPTE_30
   */
  public MidiFileFormat(int type, float divisionType, int resolution, int bytes,
      long microseconds) {

    this.type = type;
    this.divisionType = divisionType;
    this.resolution = resolution;
    this.byteLength = bytes;
    this.microsecondLength = microseconds;
    this.properties = null;
  }


  /**
   * Construct a <code>MidiFileFormat</code> with a set of properties.
   *
   * @param type the MIDI file type (0, 1, or 2)
   * @param divisionType the timing division type (PPQ or one of the SMPTE types)
   * @param resolution the timing resolution
   * @param bytes the length of the MIDI file in bytes, or UNKNOWN_LENGTH if not known
   * @param microseconds the duration of the file in microseconds, or UNKNOWN_LENGTH if not known
   * @param properties a <code>Map&lt;String,Object&gt;</code> object with properties
   * @see #UNKNOWN_LENGTH
   * @see Sequence#PPQ
   * @see Sequence#SMPTE_24
   * @see Sequence#SMPTE_25
   * @see Sequence#SMPTE_30DROP
   * @see Sequence#SMPTE_30
   * @since 1.5
   */
  public MidiFileFormat(int type, float divisionType,
      int resolution, int bytes,
      long microseconds, Map<String, Object> properties) {
    this(type, divisionType, resolution, bytes, microseconds);
    this.properties = new HashMap<String, Object>(properties);
  }


  /**
   * Obtains the MIDI file type.
   *
   * @return the file's type (0, 1, or 2)
   */
  public int getType() {
    return type;
  }

  /**
   * Obtains the timing division type for the MIDI file.
   *
   * @return the division type (PPQ or one of the SMPTE types)
   * @see Sequence#Sequence(float, int)
   * @see Sequence#PPQ
   * @see Sequence#SMPTE_24
   * @see Sequence#SMPTE_25
   * @see Sequence#SMPTE_30DROP
   * @see Sequence#SMPTE_30
   * @see Sequence#getDivisionType()
   */
  public float getDivisionType() {
    return divisionType;
  }


  /**
   * Obtains the timing resolution for the MIDI file.
   * If the division type is PPQ, the resolution is specified in ticks per beat.
   * For SMTPE timing, the resolution is specified in ticks per frame.
   *
   * @return the number of ticks per beat (PPQ) or per frame (SMPTE)
   * @see #getDivisionType
   * @see Sequence#getResolution()
   */
  public int getResolution() {
    return resolution;
  }


  /**
   * Obtains the length of the MIDI file, expressed in 8-bit bytes.
   *
   * @return the number of bytes in the file, or UNKNOWN_LENGTH if not known
   * @see #UNKNOWN_LENGTH
   */
  public int getByteLength() {
    return byteLength;
  }

  /**
   * Obtains the length of the MIDI file, expressed in microseconds.
   *
   * @return the file's duration in microseconds, or UNKNOWN_LENGTH if not known
   * @see Sequence#getMicrosecondLength()
   * @see #getByteLength
   * @see #UNKNOWN_LENGTH
   */
  public long getMicrosecondLength() {
    return microsecondLength;
  }

  /**
   * Obtain an unmodifiable map of properties.
   * The concept of properties is further explained in
   * the {@link MidiFileFormat class description}.
   *
   * @return a <code>Map&lt;String,Object&gt;</code> object containing all properties. If no
   * properties are recognized, an empty map is returned.
   * @see #getProperty(String)
   * @since 1.5
   */
  public Map<String, Object> properties() {
    Map<String, Object> ret;
    if (properties == null) {
      ret = new HashMap<String, Object>(0);
    } else {
      ret = (Map<String, Object>) (properties.clone());
    }
    return (Map<String, Object>) Collections.unmodifiableMap(ret);
  }


  /**
   * Obtain the property value specified by the key.
   * The concept of properties is further explained in
   * the {@link MidiFileFormat class description}.
   *
   * <p>If the specified property is not defined for a
   * particular file format, this method returns
   * <code>null</code>.
   *
   * @param key the key of the desired property
   * @return the value of the property with the specified key, or <code>null</code> if the property
   * does not exist.
   * @see #properties()
   * @since 1.5
   */
  public Object getProperty(String key) {
    if (properties == null) {
      return null;
    }
    return properties.get(key);
  }


}
